#ifndef __STRING_H__
#define  __STRING_H__
#include<iostream>
#include<cassert>
#include<cstring>
using namespace std;
class MyString
{
private:
    enum {ALIGN =8};
    struct StrNode
    {
        int herf;
        int len;
        int capc;
        char data[];
    };
    StrNode* pstr_;
    static size_t Round_Up(size_t n)
    {
        return (n + ALIGN - 1) & ~(ALIGN - 1);//调整成8的倍数
    }
    static StrNode* My_Malloc(size_t n)
    {
        StrNode* pstr = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * n);
        if ( nullptr == pstr  )
        {
            printf("malloc error");
            exit(1);
        }
        return pstr;
    }
    static StrNode* My_Realloc(StrNode* pstr, size_t n)
    {
         StrNode * newp = (StrNode*)realloc(pstr, sizeof(StrNode) + sizeof(char) * n);
        if (nullptr == newp )
        {
            printf("reallo error");
            exit(1);
        }
        if (pstr != newp)
        {
            free(pstr);
            pstr = newp;
        }
        newp = nullptr;
        return pstr;
    }
    static void My_Free(StrNode* pstr)
    {
        free(pstr);
    }
    static StrNode* AddString(const char* fristPstr, const char* secondPstr,int n)
    {
        int NewCap = Round_Up( 2*n);
        StrNode* pnew = My_Malloc(NewCap);
        pnew->herf = 1;
        pnew->len = n;
        pnew->capc = NewCap - 1;
        pnew->data[0] = '\0';
        if (fristPstr != nullptr)
        {
            strcpy(pnew->data,  fristPstr);
           
        }
        if (secondPstr != nullptr)
        {
            strcat(pnew->data, secondPstr);
        }
        return pnew;
        

    }
    static StrNode* CloneStrNode(StrNode* old)
    {
        int len = old->len;
        int NewCap = Round_Up(len);
        StrNode* pnew = My_Malloc(NewCap);
        pnew->herf = 1;
        pnew->len = len;
        pnew->capc = NewCap - 1;
        strcpy(pnew->data, old->data);
        return pnew;

    }
    MyString(StrNode* pstr) :pstr_{ pstr } {}
public:
    
    MyString(const char * pstr =nullptr) :pstr_{nullptr}
    {
        if (nullptr != pstr)
        {


            int length = strlen(pstr);
            int Capc = Round_Up(length);
            pstr_ = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * Capc);
            if (pstr_ == nullptr)
            {
                exit(1);
            }
            pstr_->herf = 1;
            pstr_->len = length;
            pstr_->capc = Capc - 1;
            strcpy(pstr_->data ,pstr);
        }
        else
        {
            pstr_ = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * 15);
            if (nullptr == pstr_)
            {
                exit(-1);
            }
            pstr_->herf = 0;
            pstr_->len = 0;
            pstr_->capc = 15;
        }

    }
    MyString(const MyString& other) :pstr_{ other.pstr_ }
    {
        if (pstr_ != nullptr)
        {
            pstr_->herf += 1;
        }

    }
    MyString(const char val) :pstr_{nullptr}
    {
        int total = 16;
        pstr_ = My_Malloc(total);
        pstr_->herf;
        pstr_->len =  1;
        pstr_->capc = total - 1;
        pstr_->data[0] = val;
        pstr_->data[1] = '\0';
       

    }
    MyString(MyString&& other)  noexcept : pstr_{ other.pstr_ }
    {
        other.pstr_ = nullptr;

    }
    MyString& operator =(MyString&& other)  noexcept
    {
        if (this == &other)
        {
            return *this;
        }
        if (pstr_ == other.pstr_)
        {
            other.clear();
            return *this;
        }
        clear();
        this->pstr_ = other.pstr_;
        other.pstr_ = nullptr;
        return *this;
    }
    MyString operator=(const MyString& other)
    {
        if (this == &other || pstr_ == other.pstr_ )
        {
            return *this;
        }
        clear();
        pstr_ = other.pstr_;
        if (pstr_ != nullptr)
        {
            pstr_->herf += 1;
        }
        return *this;
    }
    ~MyString()
    {
        clear();
    }
    void clear()
    {
        if (pstr_ != nullptr && --pstr_->herf == 0)
        {
           My_Free(pstr_);
        }
        pstr_ = nullptr;
    }
   
public:
    size_t size() const
    {
        return pstr_ == nullptr ? 0 : pstr_->len;
    }
    size_t length() const
    {
        return size();
    }
    bool empty() const
    {
        return size() == 0;
    }
    size_t capacity ()const
    {
        return pstr_ == nullptr ? 0 : pstr_->capc;
    }
    const char* data() const
    {
        return pstr_ != nullptr ? pstr_->data : nullptr;
    }
    const char* c_str()const
    {
        return data();
    }
    char& front()
    {
        assert(pstr_ != nullptr);
         return pstr_->data[0];
    }
    const char& front() const
    {
        assert(pstr_ != nullptr);
        return pstr_->data[0];
    }
    char& back()
    {
        assert(pstr_ != nullptr);
        return pstr_->data[pstr_->len-1];
        
    }
    const char& back()const
    {
        assert(pstr_ != nullptr);
        return pstr_->data[pstr_->len-1];
    }
    char & at(const int index)
    {
        assert(pstr_ != nullptr && index >= 0 && index < pstr_->len);
        return pstr_->data[index];
    }
    const char & at(const int index) const
    {
        assert(pstr_ != nullptr && index >= 0 && index < pstr_->len);
        return pstr_->data[index];
    }
    char& operator[](const int index)
    {
        assert(pstr_ != nullptr && index >= 0 && index < pstr_->len);
        if (pstr_->herf > 1)
        {
            pstr_->herf -= 1;
            pstr_ = CloneStrNode(pstr_);
            return pstr_->data[index];
        }
        return pstr_->data[index];
    }
   const char& operator[](const int index) const
    {
        assert(pstr_ != nullptr && index >= 0 && index < pstr_->len);
        return pstr_->data[index];
    }
   void Print() const
   {
       if (pstr_ != nullptr)
       {
           cout << "ref =" << pstr_->herf << endl;
           cout << "len =" << pstr_->len << endl;
           cout << "capc =" << pstr_->capc << endl;
           cout << "data =" << pstr_->data << endl;
       }
   }
  public:
        MyString(std::initializer_list<const char> ilist):pstr_{nullptr}//初始化列表转换为mystring
        {
            int n = ilist.size();
            int total = Round_Up(n);
            pstr_ = My_Malloc(total);
            pstr_->herf = 1;
            pstr_->capc = total - 1;
            pstr_->len = n;
            std::initializer_list<const char>::iterator it = ilist.begin();
            int i = 0;
            for (; it != ilist.end(); it++)
            {
                pstr_->data[i++] = *it;
            }
            pstr_->data[i] = '\0';
        
        }
        void reserve(size_t newcap)//增容
        {
            if (newcap <= capacity()) return;
            int total = Round_Up(newcap);
            if (nullptr == pstr_ || pstr_->herf == 1)
            {
                StrNode* newdata = My_Realloc(pstr_, total);
                if (nullptr == pstr_)
                {
                    newdata->herf = 1;
                    newdata->len = 0;
                    newdata->data[0] = '\0';
                }newdata->capc = total - 1;
                pstr_ = newdata;
            }
            else
            {
                StrNode* newdata = My_Malloc(total);
                newdata->herf = 1;
                newdata->capc = total - 1;
                newdata->len = pstr_->len;
                strcpy(newdata->data,pstr_->data);
                pstr_->herf = 1;
                pstr_ = newdata;

            }
        }
        MyString operator+(const MyString& other) const
        {
            int n = this->size() + other.size();
            if (n == 0)
            {
                return MyString();
            }
            const char* pa = this->c_str();
            const char* pb = other.c_str();
            StrNode* newdata = AddString(pa, pb, n);
            return MyString(newdata);


        }
        MyString operator+(const char* p) const
        {
            int n = this->size() + (p != nullptr ? strlen(p) : 0);
            if (n == 0)
            {
                return MyString();
            }
            const char* pa = this->c_str();
            const char* pb = p;
            StrNode* newdata = AddString(pa, pb, n);
            return MyString(newdata);
        }
        MyString operator+(const char val) const
        {
            char ch[2] = { val };
            return *this + ch;
        }
        bool operator == (const MyString& other)const { return pstr_ == other.pstr_; }
        MyString& operator+=(const MyString& other)
        {
            if (pstr_ == nullptr)
            {
                *this = other;
                return *this;
            }
            if (other.pstr_ == nullptr)
            {
                return *this;
            }
            if (pstr_->herf == 1 && pstr_->capc >= pstr_->len + other.size())
            {
                strncat(pstr_->data, other.pstr_->data, other.pstr_->len);
                pstr_->len = this->size()+other.pstr_->len;
            }
            else
            {
                int n = this->size() + other.size();
                if (n == 0)
                {
                    return *this;
                }
                const char* pa = this->c_str();
                const char* pb = other.c_str();
                StrNode* newdata = AddString(pa, pb,n);
                clear();
                pstr_ = newdata;


            }
            return *this;
        }
        MyString& operator+=(const char* p )
        {
            return *this += MyString(p);
        }
        MyString& operator+=(const char val)
        {
            if (pstr_->herf == 1 && pstr_->capc - pstr_->len > 1)
            {
                pstr_->data[pstr_->len++] = val;
                pstr_->data[pstr_->len] = '\0';
            }
            else
            {
                char ch[2] = { val };
                return  *this += MyString(ch);
            }

        }
      
        typedef char* iterator;
        typedef const char* const_iterator;
        iterator begin()
        {
            return (pstr_ != nullptr ? pstr_->data : nullptr);
        }
        iterator end()
        {
            return (pstr_ != nullptr ? pstr_->data + pstr_->len : nullptr);
        }
        const_iterator begin()const
        {
            return (pstr_ != nullptr ? pstr_->data  : nullptr);
        }
        const_iterator end()const
        {
            return (pstr_ != nullptr ? pstr_->data + pstr_->len : nullptr);
        }
        const_iterator cbegin()const
        {
            return (pstr_ != nullptr ? pstr_->data : nullptr);
        }
        const_iterator cend()const
        {
            return (pstr_ != nullptr ? pstr_->data + pstr_->len : nullptr);
          }
};
MyString operator+(const char* p, const MyString& other)
{
    return MyString(p) + other;
}
MyString operator+(const char val, const MyString& other)
{
    char ch[2] = { val };
    return MyString(ch) + other;
}
#endif 